#include <stdlib.h>
#include <stdio.h>
#include <linux/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>

#define TAILLE_MAX_NOM 256
#define NB_CLIENTS 5

typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
typedef struct hostent hostent;
typedef struct servent servent;

typedef struct {
	int socket;
	char pseudo[256];

}tabSock;

tabSock t[NB_CLIENTS] ;

//int clients[5];
//char* pseudos[5];
//int position = 0;
char pseudo[256];


char **str_split (char *s, const char *ct)
{
   char **tab = NULL;

   if (s != NULL && ct != NULL)
   {
      int i;
      char *cs = NULL;
      size_t size = 1;

/* (1) */
      for (i = 0; (cs = strtok (s, ct)); i++)
      {
         if (size <= i + 1)
         {
            void *tmp = NULL;

/* (2) */
            size <<= 1;
            tmp = realloc (tab, sizeof (*tab) * size);
            if (tmp != NULL)
            {
               tab = tmp;
            }
            else
            {
               fprintf (stderr, "Memoire insuffisante\n");
               free (tab);
               tab = NULL;
               exit (EXIT_FAILURE);
            }
         }
/* (3) */
         tab[i] = cs;
         s = NULL;
      }
      tab[i] = NULL;
   }
   return tab;
}


char *str_sub (const char *s, unsigned int start, unsigned int end)
{
   char *new_s = NULL;

   if (s != NULL && start < end)
   {
/* (1)*/
      new_s = malloc (sizeof (*new_s) * (end - start + 2));
      if (new_s != NULL)
      {
         int i;

/* (2) */
         for (i = start; i <= end; i++)
         {
/* (3) */
            new_s[i-start] = s[i];
         }
         new_s[i-start] = '\0';
      }
      else
      {
         fprintf (stderr, "Memoire insuffisante\n");
         exit (EXIT_FAILURE);
      }
   }
   return new_s;
}



void* renvoi(void* sock) {

    int l;
    char message[256];
	char buffer[256];
	int longueur;
    char deco[256]=" est deconnecte";
	int *tmp = (int*) sock;
	int nouv_socket_descriptor = *tmp;
    char myPseudo[256];
	char tempo[256];

	//printf("test de : %s\n", pseudos[0]);
	//printf("test de : %s\n", pseudos[1]);
	sprintf(myPseudo, "%s",pseudo);


for(;;) {
    
    memset(buffer,0,sizeof(buffer));
        //printf("En attente du client...\n");
	if((longueur = read(nouv_socket_descriptor, buffer, sizeof(buffer))) <= 0) {
		printf("ERREUR : impossible de lire le message.");
		return;
	}
		
	printf("%s dit : ",myPseudo);
	printf("%s \n", buffer);
    sprintf(message, "%s : %s",myPseudo, buffer);
	

    // déconnexion d'un client
    if(!strcmp(buffer,"/sortir")||!strcmp(buffer,"/quit")||!strcmp(buffer,"/exit")){
        printf("Deconnexion de : %s\n", myPseudo); 
        
		memset(message,0,sizeof(message));
        sprintf(message, "%s%s", myPseudo, deco);
        close(nouv_socket_descriptor);
        for(l=0;l<5;l++){
            if(t[l].socket==nouv_socket_descriptor){
                t[l].socket=-1;
            }
        }
	strcat(message,"\n");
	
	// envoi de la notification de deconnexion aux clients encore présents
	int Indice;
	for (Indice = 0; Indice <= 4; Indice++) {
		if(t[Indice].socket!=-1) {
			if(t[Indice].socket!=nouv_socket_descriptor) {
		 		write(t[Indice].socket,message,strlen(message));
			}
		}
	}
	memset(message,0,sizeof(message));
        
    }
    else if(!strcmp(str_sub(buffer,0,1),"/p")||!strcmp(str_sub(buffer,0,1),"/w")) {
        printf("chucho\n");
	//strcpy(tempo , str_split(buffer, " "));
	//sprintf(tempo, "%s", strtok(buffer, " "));
	//strcpy(tempo, strtok(buffer, " "));	
	//printf("ici : %s", tempo);
	int Indice;
	for(Indice = 0; Indice <= 4; Indice++){
		if(!strcmp(str_sub(buffer, 3, strlen(buffer)),t[Indice].pseudo)){
			
			//strcpy(message, str_sub(buffer, 6, strlen(buffer)));
			write(t[Indice].socket,message,strlen(message));
		}
	}

	memset(message,0,sizeof(message));
    }
	else{


    strcat(message,"\n");


	int Indice;
	for (Indice = 0; Indice <= 4; Indice++) {
		if(t[Indice].socket!=-1) {
			if(t[Indice].socket!=nouv_socket_descriptor) {
		 		write(t[Indice].socket,message,strlen(message));
			}
		}
	}
	memset(message,0,sizeof(message));
	}
}

	close(nouv_socket_descriptor);
	
	return;


}

/*
ajouterPseudo(char ps[256]) {

	pseudos[position]=ps;

}*/


main(int argc, char **argv) {
    
	pthread_t nouveau_client;
	int socket_descriptor,
	nouv_socket_descriptor,
	longueur_adresse_courante;
	sockaddr_in adresse_locale,
				adresse_client_courant;
	hostent* ptr_hote;
	servent* ptr_service;
	char machine[TAILLE_MAX_NOM+1];
    
    char messageCo[256];
    int i;

	gethostname(machine, TAILLE_MAX_NOM);

	if((ptr_hote = gethostbyname(machine)) == NULL) {
		perror("ERREUR : impossible de trouver le serveur à partir de ce nom");
		exit(1);
	}

	
	for (i = 0; i <= 4; i++) {
		t[i].socket=-1;
	}
    for (i = 0; i <= 4; i++) {
		strcpy(t[i].pseudo,"vide");
	}
    
    

	bcopy((char*)ptr_hote->h_addr, (char*)&adresse_locale.sin_addr, ptr_hote->h_length);
	adresse_locale.sin_family = ptr_hote->h_addrtype;
	adresse_locale.sin_addr.s_addr = INADDR_ANY;
	
	int port = atoi(argv[1]);
	adresse_locale.sin_port = htons(port);
    printf("en attente de connexion de clients...\n");

	//printf("numero de port co serveur : %d \n",ntohs(adresse_locale.sin_port));

	if((socket_descriptor = socket(AF_INET, SOCK_STREAM,0)) < 0) {
		perror("ERREUR : impossible de créer la socket de connexion avec le client.");
		exit(1);
	}

	if((bind(socket_descriptor,(sockaddr*)(&adresse_locale), sizeof(adresse_locale))) < 0) {
		perror("ERREUR : impossible de lier la socket à l'adresse de connexion.");
		exit(1);
	}

	listen(socket_descriptor,5);

		for(;;) {
			longueur_adresse_courante = sizeof(adresse_client_courant);
			if((nouv_socket_descriptor = accept(socket_descriptor,(sockaddr*)(&adresse_client_courant),&longueur_adresse_courante)) <0 ) {
				perror("Erreur : impossibble d'accepter la connexion avec le client.");
				exit(1);
			}
        
        memset(pseudo,0,sizeof(pseudo));
        read(nouv_socket_descriptor, pseudo, sizeof(pseudo));
        printf("nouveau client connecté : %s\n", pseudo);

        char connexion[256]="Connexion de :";
        sprintf(messageCo, "%s %s \n", connexion, pseudo);
        int Indice;
        // envoi de la notification de connexion aux autres clients
		for (Indice = 0; Indice <= 4; Indice++) {
			if(t[Indice].socket!=-1) {
				if(t[Indice].socket!=nouv_socket_descriptor) {
			 		write(t[Indice].socket,messageCo,strlen(messageCo));
				}
			}
		}
        memset(messageCo,0,sizeof(messageCo));

        for (i=0; i<5;i++){
			if (t[i].socket==-1){
			    t[i].socket=nouv_socket_descriptor;
                strcpy(t[i].pseudo,pseudo);
			    break;
			}
            
	    }

        for(i=0; i<=4; i++){

        printf("allo : %s\n", t[i].pseudo); 
        }

        //sleep(2);
		if(pthread_create(&nouveau_client, NULL, renvoi, (void*)&nouv_socket_descriptor )) {
			perror("Erreur : probleme au lancement du thread");
			return 1;
		}
		

		
        //char pseudo2[256];
        //strcpy(pseudo2,pseudo);

        //ajouterPseudo(pseudo2);

		//position++;
		
        //printf("clients : %d\n", clients[0]); 


	}


close(socket_descriptor);

	

}